Almost
prime numbers are the non-prime numbers which are divisible by only a single
prime number. In this problem your job is to write a program which finds out
the number of almost prime numbers within a certain range.
Input. First line of the input file
contains an integer n (n ≤ 600) which indicates how many
sets of inputs are there. Each of the next n lines make a single set of input.
Each set contains two integer numbers low
and high (0 < low £ high
< 1012).
Output. For each
line of input except the first line you should produce one line of output. This
output line contains a single integer, which indicates how many almost prime
numbers are within the given range (inclusive) [low.. high].
Sample input |
Sample output |
3 1 10 1 20
1 5 |
3 4 1 |
sieve of Eratosthenes – binary
search
Almost prime numbers have the form pk, where p is a prime number, k ³ 2. For
example, the almost prime numbers are 4, 8, 16, 32, 9, 81, … . As high
< 1012, then from the definition of almost prime number p
< 106. Generate the array primes
if length 1000000 = 106, where primes[i] = 1 if i is prime and primes[i] = 0 otherwise.
Then generate and sort in array m all the almost primes (their amount
equals to 80070).
Let f(a,
b) be the number of almost primes
in the range [a..b]. Then
f(low, high) = f(1, high) – f(1, low
– 1)
The
number of almost primes in the range [1 .. n] equals to the position (index),
where it is possible to insert n into the sorted array m by upper
bound preserving the sorted order. The index number can be found using binary
search on array m by means of function upper_bound.
Example
Let’s generate all the almost prime
numbers in the range from 1 to 100. First write the powers of 2 not greater
than 100. Then the powers of 3, 5 and 7. The square of 11 is greater than 100,
so there are no powers of 11 among the almost primes in the range [1..100].
Sort the array:
Consider the second test case. In the
range from 1 to 20 there are 4 almost prime numbers: 4, 8, 9, 16.
Algorithm realization
Function gen_primes fills the
array primes for primality testing.
void
gen_primes(void)
{
int i, j;
for(i = 0;i
< MAX; i++) primes[i] = 1;
for(i = 2; i
< sqrt(MAX); i++)
if
(primes[i])
for(j = i
* i; j < MAX; j += i) primes[j] = 0;
}
For each
prime i put into array m the numbers i2, i3,
i4, … until the current power is not greater than 1012.
The variable ptr contains the index
of the last almost prime number that is put into array m. As the almost
primes are limited by the value 1012, we need to process 64 bit
integers (long long type). Place at the end of array m any number
greater 1012. Let it be 1012 + 1. This should be done for
binary search function to work correctly.
ptr
= -1;
for (i = 2; i
< MAX; i++)
if
(primes[i])
{
temp = i;
while
((temp *= i) < 1e12)
m[++ptr] = temp;
}
m[++ptr]
= 1e12 + 1;
Sort the
array m using STL:
sort(m,m+ptr);
Read the
number of input test cases n and for each interval [a, b] find
and print the value f(a, b) = f(1, b) – f(
scanf("%d",&n);
for(test = 1; test <= n; test++)
{
scanf("%lld %lld",&a,&b);
printf("%d\n",upper_bound(m,m+ptr,b)
- upper_bound(m,m+ptr,a-1));
}
Java realization
import java.util.*;
public class ex
{
public static
ArrayList<Long> primes = new ArrayList<Long>();
public static void
GenPrimes()
{
final int MAX_SIZE =
1000001;
BitSet bits = new
BitSet(MAX_SIZE);
bits.set(2, MAX_SIZE, true);
for (int i = 2; i
< Math.sqrt(MAX_SIZE); i++)
{
if (bits.get(i))
for (int j = i * i;
j < MAX_SIZE; j += i)
bits.set(j, false);
}
for (int i = 2; i
< MAX_SIZE; i++)
if (bits.get(i))
{
long temp = i;
while ((temp *= i) <
1000000000000L)
primes.add(temp);
}
primes.add(1000000000001L);
Collections.sort(primes);
}
public static void
main(String[] args)
{
Scanner con = new
Scanner(System.in);
int tests = con.nextInt();
GenPrimes();
for(int i = 0; i
< tests; i++)
{
Long low = con.nextLong();
Long high = con.nextLong();
int lIndex = Collections.binarySearch(primes, low);
if (lIndex < 0) lIndex =
-(lIndex + 1);
int hIndex = Collections.binarySearch(primes, high);
if (hIndex < 0) hIndex =
-(hIndex + 1); else hIndex++;
System.out.println(hIndex -
lIndex);
}
}
}